package cn.lucky.thread.security;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @Author: jianglingpeng
 * @Date: 2020/9/21
 * @Description:
 *  解决线程安全问题方式三：使用重入锁实现线程同步
 *  JDK1.5中新增了一个java.util.concurrent(JUC)包来支持线程同步.
 *  Lock和使用synchronized方法和块具有相同的基本行为和语义,并扩展了其能力
 *  Lock是一个接口,平时真正使用的是它的实现类ReentrantLock.
 *  ReentrantLock类的常用方法：
 *      ReentrantLock():创建一个实例
 *      lock()：获得锁
 *      unlock()：释放锁
 *
 *  使用Lock和synchronized两种方式的选择:
 *      当竞争资源的线程不激烈时，两者的性能差别不大。
 *      当竞争非常激烈的情况下，使用Lock要远远优于synchronized
 */
public class SynchronizedReentryLock {

    public static void main(String[] args) {
        ReentryLock reentryLock = new ReentryLock();
        new Thread(reentryLock).start();
        new Thread(reentryLock).start();
        new Thread(reentryLock).start();
        new Thread(reentryLock).start();
    }

}

class ReentryLock implements Runnable{

    private int tickets = 100;
    private Lock lock = new ReentrantLock();
    @Override
    public void run() {
        while (true){
            lock.lock();//在读取共享数据之前,获取锁
            try {
                if (tickets > 0){
                    Thread.sleep(100);
                    System.out.println("线程[" + Thread.currentThread().getName() + "] 卖出了第" + tickets + "号票");
                    tickets--;
                }else{
                    break;
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();//当前线程执行完成之后，必须释放锁
            }
        }
    }
}
